package com.example.airhockey1

import android.content.Context
import android.opengl.GLES30.*
import android.opengl.GLSurfaceView
import java.io.BufferedReader
import java.io.InputStreamReader
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.FloatBuffer
import javax.microedition.khronos.egl.EGLConfig
import javax.microedition.khronos.opengles.GL10

class AirHockeyView(context: Context) : GLSurfaceView(context){

    init {
        setEGLContextClientVersion(3) // 设置 OpenGL ES 3.0
        setRenderer(AirHockeyRenderer())
    }

    private inner class AirHockeyRenderer : GLSurfaceView.Renderer {
        private var program: Int = 0
        private var uColorLocation: Int = 0

        private lateinit var vertexBuffer: FloatBuffer

        private var tableVerticesWithTriangles: FloatArray = floatArrayOf( // Triangle 1
            -0.5f, -0.5f,
            0.5f, 0.5f,
            -0.5f, 0.5f,  // Triangle 2

            -0.5f, -0.5f,
            0.5f, -0.5f,
            0.5f, 0.5f,  // Line 1

            -0.5f, 0f,
            0.5f, 0f,  // Mallets

            0f, -0.25f,
            0f, 0.25f
        )

        override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {
            glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

            program = createProgram(loadShader(GL_VERTEX_SHADER, "simple_vertex_shader.glsl"),
                loadShader(GL_FRAGMENT_SHADER, "simple_fragment_shader.glsl"))

            // Get the location of the uniform variable u_Color
            uColorLocation = glGetUniformLocation(program, "u_Color")

            // Initialize the vertex buffer
            vertexBuffer = ByteBuffer.allocateDirect(tableVerticesWithTriangles.size * Float.SIZE_BYTES)
                            .order(ByteOrder.nativeOrder())
                            .asFloatBuffer()
            vertexBuffer.put(tableVerticesWithTriangles)
            vertexBuffer.position(0)

            glVertexAttribPointer(0, 2, GL_FLOAT,
                false, 0, vertexBuffer);

            glEnableVertexAttribArray(0);
        }

        override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
            glViewport(0, 0, width, height);
        }

        override fun onDrawFrame(gl: GL10?) {
            glClear(GL_COLOR_BUFFER_BIT);

            glUseProgram(program)

            glUniform4f(uColorLocation, 1.0f, 1.0f, 1.0f, 1.0f);		
            glDrawArrays(GL_TRIANGLES, 0, 6);
            
            // Draw the center dividing line.
            glUniform4f(uColorLocation, 1.0f, 0.0f, 0.0f, 1.0f);		
            glDrawArrays(GL_LINES, 6, 2); 
            
            // Draw the first mallet blue.        
            glUniform4f(uColorLocation, 0.0f, 0.0f, 1.0f, 1.0f);		
            glDrawArrays(GL_POINTS, 8, 1);

            // Draw the second mallet red.
            glUniform4f(uColorLocation, 1.0f, 0.0f, 0.0f, 1.0f);		
            glDrawArrays(GL_POINTS, 9, 1);
        }

        private fun loadShader(type: Int, filename: String): Int {
            val shaderSource = readShaderFileFromAssets(context, filename)
            val shader = glCreateShader(type)
            glShaderSource(shader, shaderSource)
            glCompileShader(shader)
            val compiled = IntArray(1)
            glGetShaderiv(shader, GL_COMPILE_STATUS, compiled, 0)
            if (compiled[0] == 0) {
                glDeleteShader(shader)
                throw RuntimeException("Could not compile shader: $filename")
            }
            return shader
        }

        private fun createProgram(vertexShader: Int, fragmentShader: Int): Int {
            val program = glCreateProgram()
            glAttachShader(program, vertexShader)
            glAttachShader(program, fragmentShader)
            glLinkProgram(program)
            val linkStatus = IntArray(1)
            glGetProgramiv(program, GL_LINK_STATUS, linkStatus, 0)
            if (linkStatus[0] == 0) {
                glDeleteProgram(program)
                throw RuntimeException("Could not link program")
            }
            return program
        }

        private fun readShaderFileFromAssets(context: Context, filename: String): String {
            val reader = BufferedReader(InputStreamReader(context.assets.open(filename)))
            val builder = StringBuilder()
            var line: String?
            while (reader.readLine().also { line = it } != null) {
                builder.append(line).append("\n")
            }
            reader.close()
            return builder.toString()
        }

    }
}